typedef long jsvalue;
typedef struct jsframe jsframe;
typedef struct jscontext jscontext;
typedef struct jsobject jsobject;
typedef struct jsdouble jsdouble;
typedef struct jsstring jsstring;
typedef struct jsarray jsarray;
typedef struct jsfunction jsfunction;
typedef struct jsfield jsfield;

struct jsstackroot;
struct jsroot;

struct jsframe {
	jsvalue *slots;
	jsvalue *callFrame;
	struct jsframe *outer;
	int slotCount, callFrameCount;
	int refCount;
	struct jsframe *previousFrame;
	struct jsstackroot *stackRoots;
	jsvalue source, frame;
	int line;
};

struct jscontext
{
	jsvalue *slots;
	int slotCount;

	jsframe *topOfStack;
	int currentDepth;
	unsigned char *breakpointFlags;
	int breakpointCount;
	short *breakpointLines;
	const char **breakpointScripts;
	unsigned char *mallocBuffer;
	int mallocBufferLen;
	int memusage, objusage, objcount, maxobjcount;
	struct jsroot *roots;
	
	jsobject *firstObject;
	jsdouble *firstDouble;
	jsstring *firstString;
	
	jsdouble *freeDouble;
	jsobject *freeObject;
	jsarray *freeArray;
	jsfunction *freeFunction;
	jsfield *freeField;
	jsstring *freeString;
	
};

#define GLOBAL_EVENT 15
#define GLOBAL_UI 9
#define GLOBAL_SYSTEM 13

#define JSVAL_VOID 0
#define JSVAL_NULL 0x80000001
#define INT_TO_JSVAL(i)         (((jsvalue)(i) << 1) | 1)
#define JSVAL_FALSE             6
#define JSVAL_TRUE              14

void initRuntime();
jscontext *jsnewcontext(int slotCount);
jscontext *jsnewdebugcontext(int slotCount, int breakpointCount, short *breakpointLines, const char **breakpointScripts);

jsvalue jsloadimage(jscontext *cx, const char *imgName);

void jsDebugCheckBreakpoint(jscontext *cx, int breakpointIdx, int line);

jsvalue bindFunction(jscontext *cx, jsvalue (*proc)(jscontext *, jsframe *, jsvalue, jsvalue *, int));
jsvalue jsclosure(jscontext *cx, jsvalue (*proc)(jscontext *, jsframe *, jsvalue, jsvalue *, int), jsframe *frame);
jsvalue jsinvoke(jscontext *cx, jsvalue func, jsvalue thisArg, jsvalue *params, int paramCount);

jsvalue jsle(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jslt(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsge(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsgt(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jseq(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsne(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jseqeq(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsnene(jscontext *cx, jsvalue v, jsvalue v2);

jsvalue jsnot(jscontext *cx, jsvalue v);
jsvalue jsneg(jscontext *cx, jsvalue v);
jsvalue jsinc(jscontext *cx, jsvalue v);
jsvalue jsdec(jscontext *cx, jsvalue v);

jsvalue jsand(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsor(jscontext *cx, jsvalue v, jsvalue v2);

jsvalue jsadd(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jssub(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsdiv(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsmul(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jslsh(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsrsh(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsursh(jscontext *cx, jsvalue v, jsvalue v2);
jsvalue jsnum(jscontext *cx, double v);
jsvalue jsnumi(jscontext *cx, int v);
jsvalue jsnumconst(jscontext *cx, double v);
jsvalue jsstrconst(jscontext *cx, void *str, int len);
jsvalue jsnewarray(jscontext *cx);
jsvalue jsnewobject(jscontext *cx);
void jspush(jscontext *cx, jsvalue arr, jsvalue v);

jsvalue jsnew(jscontext *cx, jsvalue cls, jsvalue *params, int paramCount);

jsvalue jsget(jscontext *cx, jsvalue v, int h,  const char *elem);
jsvalue jsgett(jscontext *cx, jsvalue v, int h, jsvalue elem);
jsvalue jsgetattrt(jscontext *cx, jsvalue v, int h, jsvalue elem);
jsvalue jsgetdesct(jscontext *cx, jsvalue v, int h, jsvalue elem);
void jsset(jscontext *cx, jsvalue v, int h, const char *elem, jsvalue v2);
void jssett(jscontext *cx, jsvalue v, int h, jsvalue elem, jsvalue v2);
jsvalue jsgetelem(jscontext *cx, jsvalue v, jsvalue elem);
void jssetelem(jscontext *cx, jsvalue v, jsvalue elem, jsvalue v2);

jsframe *enterStack(jscontext *cx, jsframe *outer, int slotCount, int callCount);
jsframe *enterStackDebug(jscontext *cx, jsframe *outer, int slotCount, int callCount, jsvalue source, jsvalue frame);
void leaveFrame(jscontext *cx, jsframe *f);

int ifeq(jsvalue v);
int ifne(jsvalue v);
